package com.pactera.madp.cp.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.additional.query.impl.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mysql.cj.util.StringUtils;
import com.pactera.madp.admin.api.constant.SyncConstant;
import com.pactera.madp.admin.api.dto.SyncSysDept;
import com.pactera.madp.admin.api.dto.WxEmpDto;
import com.pactera.madp.admin.api.entity.SysUser;
import com.pactera.madp.admin.api.entity.SysWxDeptRelation;
import com.pactera.madp.admin.api.feign.RemoteSyncSysService;
import com.pactera.madp.admin.api.feign.RemoteUserService;
import com.pactera.madp.admin.api.vo.WxEmpVo;
import com.pactera.madp.common.core.constant.CommonConstants;
import com.pactera.madp.common.core.constant.SecurityConstants;
import com.pactera.madp.common.core.exception.CheckedException;
import com.pactera.madp.common.core.util.R;
import com.pactera.madp.common.security.util.SecurityUtils;
import com.pactera.madp.cp.api.bo.EmpSearchConditionBO;
import com.pactera.madp.cp.api.bo.SyncWxOrgBo;
import com.pactera.madp.cp.api.dto.EmployeeExcelDTO;
import com.pactera.madp.cp.api.dto.EmployeeExcelErrorExitDTO;
import com.pactera.madp.cp.api.dto.emp.*;
import com.pactera.madp.cp.api.em.permission.ReqPerEnum;
import com.pactera.madp.cp.api.em.workemployee.ContactAuthEnum;
import com.pactera.madp.cp.api.em.workemployee.EmployeeStatusEnum;
import com.pactera.madp.cp.api.em.workupdatetime.TypeEnum;
import com.pactera.madp.cp.api.entity.*;
import com.pactera.madp.cp.api.entity.sync.SyncWxOrgRelation;
import com.pactera.madp.cp.api.feign.RemoteDeptService;
import com.pactera.madp.cp.api.page.SubPage;
import com.pactera.madp.cp.api.vo.WorkEmployeeVO;
import com.pactera.madp.cp.common.constant.Constants;
import com.pactera.madp.cp.common.util.*;
import com.pactera.madp.cp.config.WxAvatarUploadConfig;
import com.pactera.madp.cp.handler.CorpContextHolder;
import com.pactera.madp.cp.mapper.WorkEmployeeMapper;
import com.pactera.madp.cp.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @description: 通讯录服务
 * @author: zhaojinjian
 * @create: 2020-11-23 16:02
 **/
@Service
@Slf4j
public class WorkEmployeeServiceImpl extends ServiceImpl<WorkEmployeeMapper, WorkEmployeeEntity> implements IWorkEmployeeService {

    @Autowired
    private IWorkEmployeeDepartmentService workEmployeeDepartmentService;
    @Autowired
    @Lazy
    private IWorkDeptService deptService;
    @Autowired
    private  IWorkContactService iWorkContactService;
    @Autowired
    private  IWorkEmployeeService iWorkEmployeeService;
    @Autowired
    private  IWorkContactEmployeeService iWorkContactEmployeeService;
    @Autowired
    private IWorkEmployeeStatisticService employeeStatisticService;
    @Autowired
    private IWorkEmployeeDepartmentService employeeDepartmentService;
    @Autowired
    private IWorkUpdateTimeService workUpdateTimeService;
    @Autowired
    private RemoteUserService remoteUserService;
    @Autowired
    private EmployeeExcelErrorService employeeExcelErrorService;
    @Autowired
    private WxSysDeptRelationService wxSysDeptRelationService;
    @Autowired
    private RemoteSyncSysService remoteSyncSysService;
    @Autowired
    private WxCallbackEmployeeServiceImp wxCallbackEmployeeServiceImp;
    @Autowired
    private EmployeeInheritService employeeInheritService;
    @Autowired
    private WxAvatarUploadConfig wxAvatarUploadConfig;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RemoteDeptService remoteDeptService;

    /**
     * @description 企业服务
     * @author zhaojinjian
     * @createTime 2020/12/12 16:56
     */
    @Autowired
    private ICorpService corpService;

    private static Map<Integer, List<String>> followUserMap = new HashMap<>();

    /**
     * 同步部门和成员
     *
     * @param corpId
     */
    @Override
    public void synWxEmployee(int corpId) {
        syncDepartment(corpId);
        syncEmployee(corpId);
        synSysUserAndDept(corpId);
        workUpdateTimeService.updateSynTime(corpId, TypeEnum.EMPLOYEE);
    }

    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public void syncDepartment(int corpId) {
        // 获取新增更新列表
        String key = RedisUtil.buildKey(Constants.SYNC_ORG_ORDER_LIST, DateUtil.format(new Date(), Constants.DATE_FORMAT));
        List<SyncWxOrgBo> orderBoList = redisTemplate.opsForList().range(key, 0, -1);
        redisTemplate.delete(key);

        // 获取删除列表
//        key = RedisUtil.buildKey(Constants.SYNC_ORG_DEL_LIST, DateUtil.format(new Date(), Constants.DATE_FORMAT));
//        List<Integer> delList = redisTemplate.opsForList().range(key, 0, -1);
//        redisTemplate.delete(key);

        // 新增更新业务对象转换
        List<WXDepartmentDTO> wxDepartmentDTOList = new ArrayList<>();
        orderBoList.forEach(bo -> {
            WXDepartmentDTO dto = new WXDepartmentDTO();
            dto.setId(bo.getWxDeptId());
            dto.setName(bo.getOrgName());
            dto.setParentid(bo.getWxParentId());
            dto.setAddress(bo.getOrgAddr());
            dto.setOrder(1);
            wxDepartmentDTOList.add(dto);
        });

        //查询企业微信端部门列表
//        String result = WxApiUtils.requestDepartmentListApi(corpId, null);
//        log.debug(" >>>>>>> 微信部门列表: " + result);
//        if (null == result) {
//            log.error(">>>>>>> 微信部门列表获取失败: null");
//            return;
//        }
//        List<WXDepartmentDTO> wxDepartmentDTOList = JSONArray.parseArray(result, WXDepartmentDTO.class);
        if (null == wxDepartmentDTOList || wxDepartmentDTOList.isEmpty()) {
            return;
        }
        Map<Integer, WXDepartmentDTO> wxDeptMap = new HashMap<>(0);
        for (WXDepartmentDTO e : wxDepartmentDTOList) {
            wxDeptMap.put(e.getId(), e);
        }

        //查询本地部门列表
        List<WorkDeptEntity> workDeptEntityList = deptService.lambdaQuery()
                .eq(WorkDeptEntity::getCorpId, corpId)
                .list();
        Map<Integer,WorkDeptEntity> localDeptMap = new HashMap<>();
        for(WorkDeptEntity localDept : workDeptEntityList) {
            localDeptMap.put(localDept.getWxDepartmentId(), localDept);
        }

        //过滤新增
        for (WorkDeptEntity wde : workDeptEntityList) {
            wxDeptMap.remove(wde.getWxDepartmentId());
        }

        //过滤删除
        List<WorkDeptEntity> updateList = new ArrayList<>();
        for (WXDepartmentDTO wxDept : wxDepartmentDTOList) {
            WorkDeptEntity e = localDeptMap.remove(wxDept.getId());
            if (e != null) {
                //过滤更新
                e.setName(wxDept.getName());
                e.setAddress(wxDept.getAddress());
                updateList.add(e);
            }
        }

        //更新
        if (!updateList.isEmpty()) {
            deptService.updateBatchById(updateList);
        }

        //新增
        List<WorkDeptEntity> insertList = new ArrayList<>();
        wxDeptMap.forEach((integer, wxDepartmentDTO) -> {
            WorkDeptEntity entity = new WorkDeptEntity();
            entity.setWxDepartmentId(wxDepartmentDTO.getId());
            entity.setCorpId(corpId);
            entity.setName(wxDepartmentDTO.getName());
            entity.setParentId(getMainDepartmentId(corpId, wxDepartmentDTO.getParentid()));
            entity.setWxParentid(wxDepartmentDTO.getParentid());
            entity.setOrder(wxDepartmentDTO.getOrder());
            entity.setAddress(wxDepartmentDTO.getAddress());
            insertList.add(entity);
        });
        if (!insertList.isEmpty()) {
            deptService.insertDeptments(insertList,corpId);
        }

        //删除
        List<Integer> delList = new ArrayList<>();
        localDeptMap.forEach((wxDeptId, workDeptEntity) -> {
            delList.add(workDeptEntity.getId());
        });

        //删除部门和成员关联
        if (!delList.isEmpty()){
            deptService.removeByIds(delList);
            QueryWrapper<WorkEmployeeDepartmentEntity> delWrapper = new QueryWrapper<>();
            delWrapper.in("department_id",delList);
            employeeDepartmentService.remove(delWrapper);
        }
    }

    @Override
    public void syncEmployee(int corpId) {
        RedisUtil.del(Constants.SYNC_FIRST_EMP);

        // 获取本地当前全部成员
        List<WorkEmployeeEntity> emps = this.list();
        Map<String, WorkEmployeeEntity> allEmpMap = new HashMap<>();
        emps.forEach(e -> allEmpMap.put(e.getWxUserId(), e));

        // 获取删除列表
        String key = RedisUtil.buildKey(SyncConstant.SYNC_WX_ORG_DEL_LIST, DateUtil.format(new Date(), Constants.DATE_FORMAT));
        List<SyncWxOrgRelation> delList = redisTemplate.opsForList().range(key, 0, -1);

        // 获取根和叶子机构
        List<SyncWxOrgRelation> relations = redisTemplate.opsForList().range(Constants.SYNC_ORG_LEAF_ROOT, 0, -1);
        redisTemplate.delete(Constants.SYNC_ORG_LEAF_ROOT);

        List<Integer> departmentIds = new ArrayList<>();
        relations.forEach(re -> departmentIds.add(re.getWxDeptId()));
        if (delList != null && !delList.isEmpty()) {
            delList.forEach(re -> departmentIds.add(re.getWxDeptId()));
        }

        for (Integer wxDeptId : departmentIds) {
            syncEmpByWxDepartId(corpId, wxDeptId, allEmpMap);
        }
        RedisUtil.del(Constants.SYNC_FIRST_EMP);
    }

    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public void syncEmployeeStatistic(int corpId) {
        // 获取成员信息
        List<WorkEmployeeEntity> employeeEntityList = lambdaQuery()
                .eq(WorkEmployeeEntity::getCorpId, corpId)
                .list();

        for (WorkEmployeeEntity emp : employeeEntityList) {
            String result = WxApiUtils.getUserBehaviorData(corpId, emp.getWxUserId());
            log.debug(" >>>>>>>>> 微信员工客户统计数据: " + result);
            if (null == result) {
                log.error(" >>>>>>>>> 微信员工客户统计数据同步失败: null");
                continue;
            }

            List<WXEmpStatisticDTO> statisticDTOList = JSONArray.parseArray(result, WXEmpStatisticDTO.class);
            if (null == statisticDTOList || statisticDTOList.isEmpty()) {
                log.error("获取微信员工统计数据");
                return;
            }
            WXEmpStatisticDTO dto = statisticDTOList.get(0);
            WorkEmployeeStatisticEntity entity = employeeStatisticService.getOne(Wrappers.<WorkEmployeeStatisticEntity>lambdaQuery()
                    .eq(WorkEmployeeStatisticEntity::getEmployeeId, emp.getId())
                    .eq(WorkEmployeeStatisticEntity::getCorpId, emp.getCorpId())
                    .eq(WorkEmployeeStatisticEntity::getSynTime,LocalDateTime.ofEpochSecond(dto.getStatTime(),0, ZoneOffset.ofHours(8))));
            if (entity == null) {
                entity = new WorkEmployeeStatisticEntity();
            }
            entity.setEmployeeId(emp.getId());
            entity.setNewApplyCnt(dto.getNewApplyCnt());
            entity.setNewContactCnt(dto.getNewContactCnt());
            entity.setChatCnt(dto.getChatCnt());
            entity.setMessageCnt(dto.getMessageCnt());
            entity.setCorpId(corpId);
            if (dto.getReplyPercentage() != null) {
                entity.setReplyPercentage((int) (dto.getReplyPercentage() * 100));
            } else {
                entity.setReplyPercentage(0);
            }
            if (dto.getAvgReplyTime() == null) {
                entity.setAvgReplyTime(0);
            } else {
                entity.setAvgReplyTime(dto.getAvgReplyTime());
            }
            entity.setNegativeFeedbackCnt(dto.getNegativeFeedbackCnt());
            entity.setSynTime(LocalDateTime.ofEpochSecond(dto.getStatTime(),0, ZoneOffset.ofHours(8)));
            employeeStatisticService.saveOrUpdate(entity);
        }
    }

    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public void syncEmpByWxDepartId(int corpId, int wxDepartmentId, Map<String,WorkEmployeeEntity> allEmpMap) {
        // 获取缓存的人员列表
//        String key = Constants.SYNC_PSN_BY_ORG + wxDepartmentId;
//        List<SyncPsnInfoBo> psnList = redisTemplate.opsForList().range(key, 0, -1);

        // 业务对象转换
//        List<WXEmployeeDTO> wxEmployeeDTOList = new ArrayList<>();
//        psnList.forEach(p -> {
//            WXEmployeeDTO dto = new WXEmployeeDTO();
//            dto.setUserid(p.getJobNo());
//            dto.setName(p.getUserName());
//            dto.setMainDepartment(wxDepartmentId);
//            dto.setMobile(p.getMobile());
//            dto.setGender(StrUtil.equals(Constants.SYNC_SEX_FLAG, p.getSex()) ? 1 : 2);
//            //dto.setStatus(); //这里状态只能依次调用微信API获取
//            List<Integer> deppartments = new ArrayList<>();
//            deppartments.add(wxDepartmentId);
//            dto.setDepartment(deppartments);
//
//        });

        String result = WxApiUtils.requestUserListApi(corpId, wxDepartmentId);
        log.debug(" >>>>>> 微信部门下成员详情列表: " + result);

        List<WXEmployeeDTO> wxEmployeeDTOList = JSONArray.parseArray(result, WXEmployeeDTO.class);
        if (null == wxEmployeeDTOList) {
            wxEmployeeDTOList = new ArrayList<>();
        }
        List<WorkEmployeeEntity> employeeEntityList = this.lambdaQuery()
                .eq(WorkEmployeeEntity::getWxMainDepartmentId, wxDepartmentId)
                .eq(WorkEmployeeEntity::getCorpId, corpId)
                .list();

        //第一次同步数据，防重处理
        if(employeeEntityList.isEmpty() && !wxEmployeeDTOList.isEmpty()) {
            for(WXEmployeeDTO dto : wxEmployeeDTOList) {
                boolean flag = RedisUtil.isMembers(Constants.SYNC_FIRST_EMP, dto.getUserid());
                if(flag) {
                    RedisUtil.del(Constants.SYNC_FIRST_EMP);
                    throw new CheckedException("存在一个成员对应多个部门"+dto.getUserid());
                }else{
                    RedisUtil.addToSet(Constants.SYNC_FIRST_EMP, dto.getUserid());
                }
            }
        }

        Map<String, WXEmployeeDTO> wxEmpMap = new HashMap<>(0);
        for (WXEmployeeDTO e : wxEmployeeDTOList) {
            wxEmpMap.put(e.getUserid(), e);
        }
        Map<String, WorkEmployeeEntity> localMap = new HashMap<>(0);
        for (WorkEmployeeEntity e : employeeEntityList ) {
            localMap.put(e.getWxUserId(),e);
        }

        // 获取成员职位信息
        Map<String, String> psnJobInfo = JSONUtil.toBean((String) RedisUtil.get(Constants.SYNC_PSN_JOB_INFO), Map.class);
        // 获取成员资质信息
        Map<String, String> qualifInfo = JSONUtil.toBean((String) RedisUtil.get(Constants.SYNC_QUALIF_INFO), Map.class);

        //更新成员列表
        List<WorkEmployeeEntity> updateEmpList = new ArrayList<>();

        //过滤企业微信删除成员
        for (WXEmployeeDTO e : wxEmployeeDTOList) {
            WorkEmployeeEntity emp = localMap.remove(e.getUserid());
            // 过滤企业微信更新成员
            if (emp != null) {
                emp.setName(e.getName());
                emp.setStatus(e.getStatus());
                emp.setMobile(e.getMobile());
                emp.setAvatar(e.getAvatar());
                emp.setThumbAvatar(e.getThumbAvatar());
                emp.setPosition(psnJobInfo.get(e.getUserid()));
                emp.setExtattr(qualifInfo.get(e.getUserid()));
                updateEmpList.add(emp);
            }
        }
        //不是删除，只是调整部门处理
        List<WorkEmployeeDepartmentEntity> delExclude = new ArrayList<>();
        localMap.forEach((wxUserId, emp) -> {
            String wxUser = WxApiUtils.getUser(wxUserId, corpId);
            if (StrUtil.isNotEmpty(wxUser)) {
                WXEmployeeDTO wxDto = JSONUtil.toBean(wxUser, WXEmployeeDTO.class);
                // 添加到更新列表
                WorkDeptEntity dept = deptService.getOne(Wrappers.<WorkDeptEntity>lambdaQuery()
                        .eq(WorkDeptEntity::getWxDepartmentId, wxDto.getMainDepartment()));
                emp.setMainDepartmentId(dept.getId());
                emp.setWxMainDepartmentId(dept.getWxDepartmentId());
                updateEmpList.add(emp);
                WorkEmployeeDepartmentEntity wd = new WorkEmployeeDepartmentEntity();
                wd.setEmployeeId(emp.getId());
                wd.setDepartmentId(emp.getMainDepartmentId());
                delExclude.add(wd);
            }
        });


        //过滤企业微信新增成员
        for (WorkEmployeeEntity e : employeeEntityList) {
            wxEmpMap.remove(e.getWxUserId());
        }
        //不是新增，只是调整部门处理
        List<String> newExclude = new ArrayList<>();
        Set<String> keys = allEmpMap.keySet();
        wxEmpMap.forEach((wxUserId, e) -> {
            for (String _wxUserId : keys) {
                if (StrUtil.equals(wxUserId, _wxUserId)) {
                    newExclude.add(wxUserId);
                    break;
                }
            }
        });
        if (!newExclude.isEmpty()) {
            newExclude.forEach(wxUserId -> wxEmpMap.remove(wxUserId));
        }

        // 更新成员
        if (!updateEmpList.isEmpty()) {
            this.updateBatchById(updateEmpList);
        }
        if (!delExclude.isEmpty()) {
            // 更新成员与部门关联
            delExclude.forEach(wd -> {
                workEmployeeDepartmentService.update(wd, Wrappers.<WorkEmployeeDepartmentEntity>lambdaQuery()
                        .eq(WorkEmployeeDepartmentEntity::getEmployeeId, wd.getEmployeeId()));
            });
        }

        // 删除成员
        if (!localMap.isEmpty()){
            for (WorkEmployeeEntity e : localMap.values()) {
                if (e.getWxMainDepartmentId()==wxDepartmentId){
                    remove(Wrappers.<WorkEmployeeEntity>lambdaQuery().eq(WorkEmployeeEntity::getWxUserId,e.getWxUserId()));
                    log.info("删除成员：{}", e.getWxUserId());
                }
            }
        }

        // 新增成员
        List<WorkEmployeeEntity> newEmployeeEntityList = new ArrayList<>();
        wxEmpMap.forEach((key, wxe) -> {
            // 设置成员职位
            wxe.setPosition(psnJobInfo.get(wxe.getUserid()));
            WorkEmployeeEntity employee = transWxEmpDtoToEmpEntity(corpId, wxe);
            employee.setExtattr(qualifInfo.get(wxe.getUserid()));
            newEmployeeEntityList.add(employee);
        });

        if (!newEmployeeEntityList.isEmpty()) {
            saveBatch(newEmployeeEntityList);
            // 更新成员与部门表索引
            for (WXEmployeeDTO dto : wxEmpMap.values()) {
                updateEmpDeptIndex(corpId, dto);
            }
        }
    }

    private List<String> getFollowUserList(int corpId) {
        List<String> list = followUserMap.get(corpId);
        if (list == null) {
            String followUserStr = WxApiUtils.requestFollowUserListApi(corpId);
            List<String> tempList = JSONArray.parseArray(followUserStr, String.class);
            if (tempList != null && !tempList.isEmpty()) {
                list = tempList;
                followUserMap.put(corpId, list);
            }
        }
        return list;
    }

    @Override
    public int getMainDepartmentId(int corpId, int wxDepartmentId) {
        if (wxDepartmentId == 0) {
            return 0;
        }
        try {
            WorkDeptEntity workDeptEntity = new WorkDeptEntity();
            workDeptEntity.setCorpId(corpId);
            workDeptEntity.setWxDepartmentId(wxDepartmentId);
            return deptService.lambdaQuery()
                    .eq(WorkDeptEntity::getCorpId, corpId)
                    .eq(WorkDeptEntity::getWxDepartmentId, wxDepartmentId)
                    .one()
                    .getId();
        } catch (Exception e) {
            // 部门 ID 不存在
            log.error(">>>>>>>>> 获取部门 id 出错, 部门 wxDepartmentId: " + wxDepartmentId + "不存在");
        }
        return 0;
    }

    @Override
    public WorkEmployeeEntity getCurrentStatus() {
        Integer userId = SecurityUtils.getUser().getId();
        Integer corpId = CorpContextHolder.getCorpId();
        WorkEmployeeEntity one = this.getOne(Wrappers.<WorkEmployeeEntity>query().eq("log_user_id", userId).eq("corp_id", corpId));
        return one;
    }

    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public void insertEmployee(int corpId, WXEmployeeDTO dto) {
        WorkEmployeeEntity employee = transWxEmpDtoToEmpEntity(corpId, dto);
        save(employee);
        updateEmpDeptIndex(corpId, dto);
    }

    private WorkEmployeeEntity transWxEmpDtoToEmpEntity(int corpId, WXEmployeeDTO dto) {
        WorkEmployeeEntity employee = new WorkEmployeeEntity();
        employee.setWxUserId(dto.getUserid());
        employee.setCorpId(corpId);
        employee.setName(dto.getName());
        employee.setMobile(dto.getMobile());
        employee.setPosition(dto.getPosition());
        employee.setGender(dto.getGender());
        employee.setEmail(dto.getEmail());
        employee.setAvatar(dto.getAvatar());
        employee.setThumbAvatar(dto.getThumbAvatar());
        employee.setTelephone(dto.getTelephone());
        employee.setAlias(dto.getAlias());
        employee.setStatus(dto.getStatus());
        employee.setExternalProfile(dto.getExternalProfile());
        employee.setExternalPosition(dto.getExternalPosition());
        employee.setAddress(dto.getAddress());
        employee.setOpenUserId(dto.getOpenUserid());
        employee.setWxMainDepartmentId(dto.getMainDepartment());
        employee.setMainDepartmentId(getMainDepartmentId(corpId, dto.getMainDepartment()));

        // 是否配置外部联系人权限（1.是 2.否）
        employee.setContactAuth(hasContactAuth(corpId, dto.getUserid()) ? 1 : 2);

        // 关联子账户
        /*R<UserInfo> result = remoteUserService.info(SecurityUtils.getUser().getUsername(), SecurityConstants.FROM_IN);
        String phone = ((UserInfo)result.getData()).getSysUser().getPhone();
        if(dto.getMobile().equals(phone)){
            employee.setLogUserId(SecurityUtils.getUser().getId());
        }*/

        // 头像上传本地处理
        /*String avatarUrl = dto.getAvatar();
        String thumbAvatarUrl = dto.getThumbAvatar();
        String qrCodeUrl = dto.getQrCode();

        String avatarKey = FileUtils.getFileNameOfEmpAvatar();
        String thumbAvatarKey = FileUtils.getFileNameOfEmpThumbAvatar();
        String qrCodeKey = FileUtils.getFileNameOfEmpQrCode();

        employee.setAvatar(wxAvatarUploadConfig.getEnabled() ? FilesUtil.getFileURI(avatarKey) : avatarUrl);
        employee.setThumbAvatar(wxAvatarUploadConfig.getEnabled() ? FilesUtil.getFileURI(thumbAvatarKey) : avatarUrl);
        employee.setQrCode(FilesUtil.getFileURI(qrCodeKey));

        if (wxAvatarUploadConfig.getEnabled()) {
            DownUploadQueueUtils.uploadFileByUrl(avatarKey, avatarUrl);
            DownUploadQueueUtils.uploadFileByUrl(thumbAvatarKey, thumbAvatarUrl);
            DownUploadQueueUtils.uploadFileByUrl(qrCodeKey, qrCodeUrl);
        }*/


        /*employee.setAvatar(avatarKey);
        employee.setThumbAvatar(thumbAvatarKey);
        employee.setQrCode(qrCodeKey);

        DownUploadQueueUtils.uploadFileByUrl(avatarKey, avatarUrl);
        DownUploadQueueUtils.uploadFileByUrl(thumbAvatarKey, thumbAvatarUrl);
        DownUploadQueueUtils.uploadFileByUrl(qrCodeKey, qrCodeUrl);*/

        return employee;
    }

    private boolean hasContactAuth(int corpId, String wxUserId) {
        return getFollowUserList(corpId).contains(wxUserId);
    }

    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public void updateEmpDeptIndex(int corpId, WXEmployeeDTO dto) {
        // 根据员工微信 id, 获取员工 id
        int empId = getEmpIdByWxUserId(corpId, dto.getUserid());

        List<WorkEmployeeDepartmentEntity> workEmployeeDepartmentEntityList = employeeDepartmentService.list(
                new QueryWrapper<WorkEmployeeDepartmentEntity>()
                        .eq("employee_id", empId)
        );

        // 循环员工微信部门 id, 获取对应部门 id
        List<Integer> depts = dto.getDepartment();
        List<Integer> orders = dto.getOrder();
        List<Integer> isLeaderInDepts = dto.getIsLeaderInDept();

        WorkEmployeeDepartmentEntity entity;

        List<Integer> hasList = new ArrayList<>();
        List<WorkEmployeeDepartmentEntity> updateList = new ArrayList<>();

        if (!workEmployeeDepartmentEntityList.isEmpty()) {
            for (int i = 0; i < depts.size(); i++) {
                int deptId = depts.get(i);
                int order = orders.get(i);
                int isLeaderInDept = isLeaderInDepts.get(i);

                // 查询对应部门 id
                int dId = getMainDepartmentId(corpId, deptId);

                for (int j = 0; j < workEmployeeDepartmentEntityList.size(); j++) {
                    entity = workEmployeeDepartmentEntityList.get(j);
                    if (dId == entity.getDepartmentId()) {
                        hasList.add(i);
                        entity.setIsLeaderInDept(isLeaderInDept);
                        entity.setOrder(order);
                        updateList.add(entity);
                        workEmployeeDepartmentEntityList.remove(entity);
                        break;
                    }
                }
            }
        }

        for (int hasIndex : hasList) {
            depts.remove(hasIndex);
            orders.remove(hasIndex);
            isLeaderInDepts.remove(hasIndex);
        }

        List<WorkEmployeeDepartmentEntity> newList = new ArrayList<>();

        for (int i = 0; i < depts.size(); i++) {
            int deptId = depts.get(i);
            int order = orders.get(i);
            int isLeaderInDept = isLeaderInDepts.get(i);

            // 查询对应部门 id
            int dId = getMainDepartmentId(corpId, deptId);

            entity = new WorkEmployeeDepartmentEntity();
            entity.setEmployeeId(empId);
            entity.setDepartmentId(dId);
            entity.setIsLeaderInDept(isLeaderInDept);
            entity.setOrder(order);

            newList.add(entity);
        }

        List<Integer> removeIds = new ArrayList<>();
        for (WorkEmployeeDepartmentEntity employeeDepartmentEntity : workEmployeeDepartmentEntityList) {
            removeIds.add(employeeDepartmentEntity.getId());
        }

        if (!removeIds.isEmpty()) {
            employeeDepartmentService.getBaseMapper().deleteBatchIds(removeIds);
        }
        if (!updateList.isEmpty()) {
            employeeDepartmentService.updateBatchById(updateList);
        }
        if (!newList.isEmpty()) {
            employeeDepartmentService.saveBatch(newList);
        }
    }

    private int getEmpIdByWxUserId(int corpId, String wxUserId) {
        // 根据员工微信 id, 获取员工 id
        WorkEmployeeEntity employeeEntity = lambdaQuery()
                .eq(WorkEmployeeEntity::getCorpId, corpId)
                .eq(WorkEmployeeEntity::getWxUserId, wxUserId)
                .one();
        if (employeeEntity == null) {
            throw new CheckedException("员工不存在");
        } else {
            return employeeEntity.getId();
        }
    }

    @Override
    public R index(EmpIndexDTO req, ReqPerEnum permission, Page page) {
        Integer corpId = CorpContextHolder.getCorpId();

        Integer status = req.getStatus();
        String name = req.getName();
        String contactAuth = req.getContactAuth();
        String mobile = req.getMobile();

        LambdaQueryChainWrapper<WorkEmployeeEntity> wrapper = lambdaQuery();
        // 设置数据权限
        setWrapperPermission(wrapper, permission);
        wrapper.select(
                WorkEmployeeEntity::getId,
                WorkEmployeeEntity::getName,
                WorkEmployeeEntity::getMobile,
                WorkEmployeeEntity::getPosition,
                WorkEmployeeEntity::getEmail,
                WorkEmployeeEntity::getThumbAvatar,
                WorkEmployeeEntity::getStatus,
                WorkEmployeeEntity::getAddress,
                WorkEmployeeEntity::getGender,
                WorkEmployeeEntity::getWxUserId
        );
        wrapper.eq(WorkEmployeeEntity::getCorpId, corpId);
        if (null != status && status > 0 && status <= 5) {
            wrapper.eq(WorkEmployeeEntity::getStatus, status);
        }
        if (null != name && !name.isEmpty()) {
            wrapper.like(WorkEmployeeEntity::getName, name);
        }
        if (null != contactAuth) {
            wrapper.eq(WorkEmployeeEntity::getContactAuth, contactAuth);
        }
        if (!StrUtil.isEmpty(mobile)) {
            wrapper.likeRight(WorkEmployeeEntity::getMobile, mobile);
        }

        wrapper.page(page);

        List<WorkEmployeeEntity> workEmployeeEntities = page.getRecords();
        List<WorkEmployeeVO> voList = new ArrayList<>();
        for (WorkEmployeeEntity emp : workEmployeeEntities) {
            WorkEmployeeVO vo = new WorkEmployeeVO();
            BeanUtil.copyProperties(emp, vo);
            voList.add(vo);
        }

        SubPage subPage = new SubPage();
        subPage.setRecords(voList);
        subPage.setCurrent(page.getCurrent());
        subPage.setSize(page.getSize());
        subPage.setTotal(page.getTotal());
        String syncTime = workUpdateTimeService.getLastUpdateTime(TypeEnum.EMPLOYEE);
        subPage.getExtraProps().put("syncTime",syncTime);
        return R.ok(subPage);

//        return ApiRespUtils.transPage(pageEntity, employeeBOList);
    }

    @Override
    public R indexWechat(EmpIndexDTO req, ReqPerEnum permission, Page page) {
        Integer corpId = CorpContextHolder.getCorpId();
        Integer status = req.getStatus();
        String name = req.getName();
        String contactAuth = req.getContactAuth();

        LambdaQueryChainWrapper<WorkEmployeeEntity> wrapper = lambdaQuery();
        // 设置数据权限
        setWrapperPermission(wrapper, permission);
        wrapper.select(
                WorkEmployeeEntity::getId,
                WorkEmployeeEntity::getName,
                WorkEmployeeEntity::getMobile,
                WorkEmployeeEntity::getPosition,
                WorkEmployeeEntity::getEmail,
                WorkEmployeeEntity::getThumbAvatar,
                WorkEmployeeEntity::getStatus,
                WorkEmployeeEntity::getAddress,
                WorkEmployeeEntity::getGender,
                WorkEmployeeEntity::getWxUserId,
                WorkEmployeeEntity::getWxUserId
        );
        wrapper.eq(WorkEmployeeEntity::getCorpId, corpId);
        if (null != status && status > 0 && status <= 5) {
            wrapper.eq(WorkEmployeeEntity::getStatus, status);
        }
        if (null != name && !name.isEmpty()) {
            wrapper.like(WorkEmployeeEntity::getName, name);
        }
        if (null != contactAuth) {
            wrapper.eq(WorkEmployeeEntity::getContactAuth, contactAuth);
        }

//        Page<WorkEmployeeEntity> pageEntity = ApiRespUtils.initPage(req);
        wrapper.page(page);

        List<WorkEmployeeEntity> workEmployeeEntities = page.getRecords();
        List<WorkEmployeeVO> voList = new ArrayList<>();
        for (WorkEmployeeEntity emp : workEmployeeEntities) {
            WorkEmployeeVO vo = new WorkEmployeeVO();
            BeanUtil.copyProperties(emp, vo);
            /*vo.setAvatar(AliyunOssUtils.getUrl(emp.getAvatar()));
            vo.setThumbAvatar(AliyunOssUtils.getUrl(emp.getThumbAvatar()));*/
            vo.setAvatar(emp.getAvatar());
            vo.setThumbAvatar(emp.getThumbAvatar());
            voList.add(vo);
        }
        SubPage subPage = new SubPage();
        subPage.setRecords(voList);
        subPage.setCurrent(page.getCurrent());
        subPage.setSize(page.getSize());
        subPage.setTotal(page.getTotal());
        String syncTime = workUpdateTimeService.getLastUpdateTimeWechat(TypeEnum.EMPLOYEE);
        subPage.getExtraProps().put("syncTime",syncTime);
        return R.ok(subPage);
    }

    /**
     * @author: yangpengwei
     * @time: 2021/3/17 11:19 上午
     * @description 权限管理查询条件配置
     */
    private void setWrapperPermission(LambdaQueryChainWrapper<WorkEmployeeEntity> wrapper, ReqPerEnum permission) {
        if (permission == ReqPerEnum.ALL) {
            return;
        }

        if (permission == ReqPerEnum.DEPARTMENT) {
            // 查询员工所属的部门 id 列表
            List<Integer> idList = employeeDepartmentService.getDeptAndChildDeptEmpIdList();

            // 将部门和子部门的员工 id 列表加入搜索 wrapper
            if (idList.size() > 0) {
                wrapper.in(WorkEmployeeEntity::getId, idList);
            }
        }

        if (permission == ReqPerEnum.EMPLOYEE) {
            int empId = AccountService.getEmpId();
            wrapper.eq(WorkEmployeeEntity::getId, empId);
        }
    }

    @Override
    public EmpSearchConditionBO searchCondition() {
        EmpSearchConditionBO searchConditionBO = new EmpSearchConditionBO();

        String syncTime = workUpdateTimeService.getLastUpdateTime(TypeEnum.EMPLOYEE);
        searchConditionBO.setSyncTime(syncTime);

        EmployeeStatusEnum[] employeeStatusEnums = EmployeeStatusEnum.values();
        List<EmpSearchConditionBO.EmpEnumBO> empEnumBOList = new ArrayList<>();
        for (EmployeeStatusEnum e : employeeStatusEnums) {
            EmpSearchConditionBO.EmpEnumBO empEnumBO = new EmpSearchConditionBO.EmpEnumBO();
            empEnumBO.setId(e.getCode());
            empEnumBO.setName(e.getMsg());
            empEnumBOList.add(empEnumBO);
        }
        searchConditionBO.setStatus(empEnumBOList);

        ContactAuthEnum[] contactAuthEnums = ContactAuthEnum.values();
        List<EmpSearchConditionBO.EmpEnumBO> empEnumBOList1 = new ArrayList<>();
        for (ContactAuthEnum e : contactAuthEnums) {
            EmpSearchConditionBO.EmpEnumBO empEnumBO = new EmpSearchConditionBO.EmpEnumBO();
            empEnumBO.setId(e.getCode());
            empEnumBO.setName(e.getMsg());
            empEnumBOList1.add(empEnumBO);
        }
        searchConditionBO.setContactAuth(empEnumBOList1);

        return searchConditionBO;
    }

    @Override
    public EmpSearchConditionBO searchConditionWechat() {
        EmpSearchConditionBO searchConditionBO = new EmpSearchConditionBO();
        String syncTime = workUpdateTimeService.getLastUpdateTimeWechat(TypeEnum.EMPLOYEE);
        searchConditionBO.setSyncTime(syncTime);
        EmployeeStatusEnum[] employeeStatusEnums = EmployeeStatusEnum.values();
        List<EmpSearchConditionBO.EmpEnumBO> empEnumBOList = new ArrayList<>();
        for (EmployeeStatusEnum e : employeeStatusEnums) {
            EmpSearchConditionBO.EmpEnumBO empEnumBO = new EmpSearchConditionBO.EmpEnumBO();
            empEnumBO.setId(e.getCode());
            empEnumBO.setName(e.getMsg());
            empEnumBOList.add(empEnumBO);
        }
        searchConditionBO.setStatus(empEnumBOList);

        ContactAuthEnum[] contactAuthEnums = ContactAuthEnum.values();
        List<EmpSearchConditionBO.EmpEnumBO> empEnumBOList1 = new ArrayList<>();
        for (ContactAuthEnum e : contactAuthEnums) {
            EmpSearchConditionBO.EmpEnumBO empEnumBO = new EmpSearchConditionBO.EmpEnumBO();
            empEnumBO.setId(e.getCode());
            empEnumBO.setName(e.getMsg());
            empEnumBOList1.add(empEnumBO);
        }
        searchConditionBO.setContactAuth(empEnumBOList1);

        return searchConditionBO;
    }

    @Override
    public R changeUser(String wxUserId,String wxExternalUserid,String id) {
        if(wxUserId.equals(id)){
            throw new CheckedException("不可转接给自己！");
        }
        //转接用户数据
        WorkEmployeeEntity newEntity = iWorkEmployeeService.getWorkEmployeeInfo(wxUserId);
        if (newEntity.getContactAuth()==2){
            return R.failed("该用户无外部联系人权限！");
        }
        //转接客户数据
        String[] contact = {wxExternalUserid};
       return employeeInheritService.updateContact(id,wxUserId,contact);
    }

    /**
     * 查看通讯录表中是否存在当前手机号，然后绑定
     *
     * @param mobile
     * @param logUserId
     */
    @Override
    public void verifyEmployeeMobile(String mobile, Integer logUserId) {
        //region 查看通讯录表中是否存在当前手机号，然后绑定
        QueryWrapper<WorkEmployeeEntity> workEmployeeWrapper = new QueryWrapper<>();
        workEmployeeWrapper.eq("mobile", mobile);
//        workEmployeeWrapper.isNull("deleted_at");
        List<WorkEmployeeEntity> myWorkEmployee = this.list(workEmployeeWrapper);
        //判断当前手机号是否存在通讯录里
        if (myWorkEmployee != null && myWorkEmployee.size() > 0) {
            myWorkEmployee.forEach(item -> {
                item.setLogUserId(logUserId);
            });
            this.updateBatchById(myWorkEmployee);
        }
        //endregion
    }

    /**
     * @Description: 获取用户通讯录详情
     * @Param:
     * @return:
     * @Author: zhaojinjian
     * @Date: 2020/11/23
     */
    @Override
    public WorkEmployeeEntity getWorkEmployeeInfo(Integer empId) {
        return this.baseMapper.selectById(empId);
    }

    /**
     * @Description: 通过userId获取用户通讯录详情
     * @Param:
     * @return:
     * @Author: zhaojinjian
     * @Date: 2020/11/23logId
     */
    @Override
    public WorkEmployeeEntity getWorkEmployeeInfoByLogId(Integer userId) {
        QueryWrapper<WorkEmployeeEntity> workEmployeeEntityQueryWrapper = new QueryWrapper();
        workEmployeeEntityQueryWrapper.eq("log_user_id",userId);
        workEmployeeEntityQueryWrapper.eq("corp_id", CorpContextHolder.getCorpId());
        return this.baseMapper.selectOne(workEmployeeEntityQueryWrapper);
    }



    /**
     *
     *
     * @description:根据wxuserid查找
     * @author: Huayu
     * @time: 2021/3/30 22:51
     */
    @Override
    public WorkEmployeeEntity getWorkEmployeeByWxUserId(String userId, String s) {
        QueryWrapper<WorkEmployeeEntity> workEmployeeEntityQueryWrapper = new QueryWrapper();
        workEmployeeEntityQueryWrapper.select(s);
        workEmployeeEntityQueryWrapper.eq("wx_user_id",userId);
        workEmployeeEntityQueryWrapper.eq("corp_id", CorpContextHolder.getCorpId());
        return this.getOne(workEmployeeEntityQueryWrapper);
    }

    @Override
    public List<WorkEmployeeEntity> countWorkEmployeesByCorpId(Integer corpId) {
        QueryWrapper<WorkEmployeeEntity> workEmployeeEntityQueryWrapper = new QueryWrapper();
        workEmployeeEntityQueryWrapper.eq("corp_id",corpId);
        return this.baseMapper.selectList(workEmployeeEntityQueryWrapper);
    }

    @Override
    public WorkEmployeeEntity getWorkEmployeeByCorpIdAndWxUserId(Integer corpId, String wxUserId) {
        return this.getOne(Wrappers.<WorkEmployeeEntity>lambdaQuery()
                .eq(WorkEmployeeEntity::getCorpId,corpId)
                .eq(WorkEmployeeEntity::getWxUserId,wxUserId),false);
    }

    @Override
    public List<Integer> getAllowEmployeesByDeptIds(List<Integer> depts) {
        List<Integer> employees = workEmployeeDepartmentService.listObjs(Wrappers.<WorkEmployeeDepartmentEntity>lambdaQuery()
                .select(WorkEmployeeDepartmentEntity::getId)
                .in(WorkEmployeeDepartmentEntity::getDepartmentId, depts), o -> Integer.parseInt(o.toString()));
        return employees;
    }

    @Override
    public Set<Integer> getEmployeeIds(List<Integer> wxDeptIds, List<String> userMobiles) {
        Set<Integer> employeeIds;
        if (userMobiles == null) {
            employeeIds = new HashSet<>();
        } else {
            employeeIds = this.baseMapper.selectList(
                    Wrappers.<WorkEmployeeEntity>lambdaQuery()
                    .select(WorkEmployeeEntity::getId)
                    .in(WorkEmployeeEntity::getMobile, userMobiles)
            ).stream().map(WorkEmployeeEntity::getId).collect(Collectors.toSet());
        }
        if (wxDeptIds != null && wxDeptIds.size() > 0) {
            employeeIds.addAll(this.baseMapper.getUsersByWxDeptIds(wxDeptIds));
        }
        return employeeIds;
    }

    @Override
    public List<Integer> getEmployeeIdsByDeptIds(List<Integer> deptIds) {
        if (deptIds.isEmpty()) {
            return new ArrayList<Integer>();
        }
        R r = remoteDeptService.getDeptsAndUsers(deptIds);
        log.info("r:{}",r);
        Map<String, Object> data = (Map) r.getData();
        List<Integer> wxDeptIds = (List<Integer>) data.get("wxDeptIds");
        List<String> userMobiles = (List<String>) data.get("userMobiles");
        Set<Integer> employeeIds = this.getEmployeeIds(wxDeptIds, userMobiles).stream().distinct().collect(Collectors.toSet());
        return new ArrayList<Integer>(employeeIds);
    }

    @Override
    public List<WorkEmployeeEntity> selectAgentEmployee(String employeeName) {
        Integer corpId = CorpContextHolder.getCorpId();
        String wxCorpId = corpService.getById(corpId).getWxCorpId();
        Integer agentId = corpService.getWxSendMsgAgentIdByWxCorpId(wxCorpId);
        String accessToken = WxApiUtils.getAccessTokenAgent(corpId, agentId);
        String requestUrl = "https://qyapi.weixin.qq.com/cgi-bin/agent/get?access_token=" + accessToken + "&agentid=" + agentId;
        String res = HttpClientUtil.doGet(requestUrl);
        log.debug("get===resp========================》" + res);
        JSONObject jsonObject = JSONObject.parseObject(res);

        JSONArray array = jsonObject.getJSONObject("allow_userinfos").getJSONArray("user");
        JSONArray parts = jsonObject.getJSONObject("allow_partys").getJSONArray("partyid");
        List<Integer> deptIds = parts.toJavaList(Integer.class);
        List<Integer> finalDeptIds = deptService.getAllAllowChilds(deptIds);
        List<Integer> employeeIds1 = getAllowEmployeesByDeptIds(finalDeptIds);

        ArrayList<String> list = new ArrayList<>();
        array.stream().forEach(item -> {
            String wxId = ((JSONObject) item).get("userid").toString();
            list.add(wxId);
        });
        QueryWrapper<WorkEmployeeEntity> wrapper = new QueryWrapper<WorkEmployeeEntity>();
        wrapper.eq("corp_id", corpId);
        if (!StringUtils.isNullOrEmpty(employeeName)) {
            wrapper.like("name", employeeName);
        }
        if ((list == null || list.isEmpty()) && employeeIds1 == null || employeeIds1.isEmpty()) {
            return new ArrayList<>();
        }
        wrapper.and(wrapper1 -> {
            if (list != null && !list.isEmpty()) {
                wrapper1.in("wx_user_id", list);
                if (employeeIds1 != null && !employeeIds1.isEmpty()) {
                    wrapper1.or()
                            .in("id", employeeIds1);
                }
            } else if (employeeIds1 != null && !employeeIds1.isEmpty()) {
                wrapper1.in("id", employeeIds1);
            }
        });
        List<WorkEmployeeEntity> employeeEntities = this.list(wrapper);

        return employeeEntities;
    }

    @Override
    public void exitExcel(HttpServletResponse response, OutputStream out) {
        EmployeeExcelDTO dto = new EmployeeExcelDTO();
        LinkedList<Integer> department = new LinkedList<>();
        LinkedList<Integer> isLeaderInDept = new LinkedList<>();
        department.add(0,1);
        department.add(1,2);
        isLeaderInDept.add(0,1);
        isLeaderInDept.add(0,0);

        dto.setWxUserId("ZhangSan");
        dto.setName("张三");
        dto.setAlias("张三的别名");
        dto.setMobile("13888888888");
        dto.setDepartment(department);
        dto.setPosition("普通员工");
        dto.setGender(1);
        dto.setEmail("sanzhang@pactera.com");
        dto.setTelephone("028-88888888");
        dto.setIsLeaderInDept(isLeaderInDept);
        dto.setEnable(0);
        dto.setToInvite(false);
        dto.setExternalPosition("高级产品经理");
        dto.setAddress("xx市xx区xx路xx号");
        dto.setMainDepartment(1);

        List<EmployeeExcelDTO> rows = CollUtil.newArrayList(dto);
        // 通过工具类创建writer
        ExcelWriter writer = ExcelUtil.getWriter(true);

        writer.addHeaderAlias("wxUserId","wxUserId");
        writer.addHeaderAlias("name","name");
        writer.addHeaderAlias("alias","alis");
        writer.addHeaderAlias("mobile","mobile");
        writer.addHeaderAlias("department","department");
        writer.addHeaderAlias("position","position");
        writer.addHeaderAlias("gender","gender");
        writer.addHeaderAlias("email","email");
        writer.addHeaderAlias("telephone","telephone");
        writer.addHeaderAlias("telephone","telephone");
        writer.addHeaderAlias("isLeaderInDept","isLeaderInDept");
        writer.addHeaderAlias("enable","enable");
        writer.addHeaderAlias("toInvite","toInvite");
        writer.addHeaderAlias("externalPosition","externalPosition");
        writer.addHeaderAlias("address","address");
        writer.addHeaderAlias("mainDepartment","mainDepartment");

        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setHeader("Content-Disposition","attachment;filename=example.xlsx");

        // 一次性写出内容，使用默认样式，强制输出标题
        writer.write(rows, true);
        writer.flush(out, true);
        // 关闭writer，释放内存
        writer.close();

        IoUtil.close(out);
    }

    @Override
    public void excelErrorMsg(HttpServletResponse response, OutputStream out) {
        List<EmployeeExcelErrorEntity> employeeExcelErrorEntities = employeeExcelErrorService.list(Wrappers.<EmployeeExcelErrorEntity>lambdaQuery()
                .eq(EmployeeExcelErrorEntity::getCorpId,CorpContextHolder.getCorpId()));
        LinkedList<EmployeeExcelErrorExitDTO> rows  = new LinkedList<>();
        employeeExcelErrorEntities.forEach(e->{
            EmployeeExcelErrorExitDTO row = new EmployeeExcelErrorExitDTO();
            BeanUtil.copyProperties(e,row);
            rows.add(row);
        });
        ExcelWriter writer = ExcelUtil.getWriter(true);

        writer.addHeaderAlias("name","姓名");
        writer.addHeaderAlias("wxUserId","企业微信id");
        writer.addHeaderAlias("errorCode","错误值");
        writer.addHeaderAlias("errorMsg","错误信息");
        writer.addHeaderAlias("excelError","Excel错误信息");
        writer.addHeaderAlias("excelName","Excel名字");

        if (rows.isEmpty()){
            EmployeeExcelErrorExitDTO row = new EmployeeExcelErrorExitDTO();
            rows.add(row);
        }
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setHeader("Content-Disposition","attachment;filename=excel-error.xlsx");

        // 一次性写出内容，使用默认样式，强制输出标题
        writer.write(rows, true);
        writer.flush(out, true);
        // 关闭writer，释放内存
        writer.close();

        IoUtil.close(out);

    }

    /**
     * 企业微信Excel导入
     * @param file
     * @return
     */
    @Override
    public R inputExcel(MultipartFile file) {
        int j = 0;
        AtomicInteger success = new AtomicInteger();
        AtomicInteger fail = new AtomicInteger();
        try {
            //将输入的文件转换为流对象
            InputStream inputStream = file.getInputStream();
            //将流对象转换为ExcelReader对象
            ExcelReader reader = ExcelUtil.getReader(inputStream,j);
            //将流对象转换为字符串
            String text = reader.getExtractor().getText();
            //将字符串通过"\n"切割
            String[] split = text.split("\n");
            //将ExcelReader对象转换为List<Map>对象
            List<Map<String, Object>> maps = reader.readAll();
            AtomicInteger i = new AtomicInteger(1);
            maps.forEach(m->{
                String department = (String) m.get("department");
                String userId = (String) m.get("wxUserId");
                String name = (String) m.get("name");
                JSONArray departments = JSONArray.parseArray(department);
                if (StrUtil.isBlank(department)||departments.isEmpty()){
                    throw new NullPointerException("第"+i.get()+"行的department不能为空");
                }
                if (StrUtil.isBlank(name)){
                    throw new NullPointerException("第"+i.get()+"行的name不能为空");
                }
                if (StrUtil.isBlank(userId)){
                    throw new NullPointerException("第"+i.get()+"行的wxUserId不能为空");
                }
            });
            List<EmployeeExcelErrorEntity> errorEntities = new LinkedList<>();
            maps.forEach(m->{
                Map<String, Object> map = new HashMap<>();
                Map<String, Object> errors = new HashMap<>();
                String userId = (String) m.get("wxUserId");
                String name = (String) m.get("name");
                String department = (String) m.get("department");
                String alias = (String) m.get("alias");
                String mobile =  m.get("mobile").toString();
                String position = (String) m.get("position");
                String email = (String) m.get("email");
                String telephone = (String) m.get("telephone");
                String isLeaderInDept = (String) m.get("isLeaderInDept");
                String externalPosition = (String) m.get("externalPosition");
                String address = (String) m.get("address");
                Integer mainDepartment = null;
                Integer gender = null;
                Integer enable = null;
                if ( m.get("mainDepartment") != null && !m.get("mainDepartment").equals("")){
                  mainDepartment  = Integer.valueOf(String.valueOf(m.get("mainDepartment"))) ;
                }

                Boolean toInvite =Boolean.valueOf (m.get("toInvite").toString()) ;
                if ( m.get("gender") != null && !m.get("gender").equals("")){
                    gender = Integer.parseInt(m.get("gender").toString());;
                }
                if ( m.get("enable") != null && !m.get("enable").equals("")){
                    enable = Integer.parseInt(m.get("enable").toString());
                }
                JSONArray departments = JSONArray.parseArray(department);
                JSONArray isLeaderInDepts = JSONArray.parseArray(isLeaderInDept);

                map.put("userid",userId);
                map.put("name",name);
                map.put("department",departments);

                if (!StrUtil.isBlank(alias)){
                    map.put("alias",alias);
                }
                if (!StrUtil.isBlank(address)){
                    map.put("address",address);
                }
                if (!StrUtil.isBlank(m.get("mainDepartment").toString())){
                    map.put("main_department",mainDepartment);
                }
                if (!StrUtil.isBlank(mobile)){
                    if(!ValidatorUtil.isMobile(mobile)){
                        errors.put("mobile","mobile格式不正确");
                    }
                    map.put("mobile",mobile);
                }
                if (!StrUtil.isBlank(position)){
                    map.put("position",position);
                }
                if (!StrUtil.isBlank(externalPosition)){
                    map.put("external_position",externalPosition);
                }
                if (!StrUtil.isBlank(email)){
                    if(!ValidatorUtil.isEmail(email)){
                        errors.put("email","email格式不正确");
                    }
                    map.put("email",email);
                }
                if (StrUtil.isBlank(email)&&StrUtil.isBlank(mobile)){
                    errors.put("email-and-mobile","email和mobile同时为空");
                }
                if (!StrUtil.isBlank(telephone)){
                    if(!ValidatorUtil.isTelephone(telephone)){
                        errors.put("telephone","telephone格式不正确");
                    }
                    map.put("telephone",telephone);
                }
                if (!StrUtil.isBlank(m.get("gender").toString())){
                    if (gender !=1 && gender != 2){
                        errors.put("gender","gender值不为1（男性）或2（女性）");
                    }
                    map.put("gender",gender);
                }
                if (!StrUtil.isBlank(m.get("enable").toString())){
                    if (enable !=0 && enable != 1){
                        errors.put("enable","enable值不为0（禁用）或1（启用）");
                    }
                    map.put("enable",enable);
                }
                if (!StrUtil.isBlank(isLeaderInDept) && !isLeaderInDepts.isEmpty()){
                    if (departments.size() != isLeaderInDepts.size()){
                        errors.put("department-isLeaderInDept","isLeaderInDept与department数目不匹配");
                    }
                    isLeaderInDepts.forEach(ili->{
                        if (Integer.parseInt(ili.toString()) != 0 && Integer.parseInt(ili.toString()) !=1){
                            errors.put("isLeaderInDept","isLeaderInDept的值必须为1或者0");
                        }
                    });
                    map.put("is_leader_in_dept",isLeaderInDepts);
                }
                if (!StrUtil.isBlank(m.get("toInvite").toString())){
                    map.put("to_invite",toInvite);
                }
                String user = WxApiUtils.createUser(map, CorpContextHolder.getCorpId());
                JSONObject jsonObject = JSONObject.parseObject(user);
                if (Integer.parseInt(jsonObject.get("errcode").toString()) !=0){
                    EmployeeExcelErrorEntity errorEntity = new EmployeeExcelErrorEntity();
                    errorEntity.setExcelError(JSONObject.toJSONString(errors));
                    errorEntity.setName(map.get("name").toString());
                    errorEntity.setWxUserId(map.get("userid").toString());
                    errorEntity.setErrorCode(Integer.valueOf(jsonObject.get("errcode").toString()));
                    errorEntity.setErrorMsg(jsonObject.get("errmsg").toString());
                    errorEntity.setCorpId(CorpContextHolder.getCorpId());
                    errorEntity.setExcelName(file.getOriginalFilename());
                    errorEntities.add(errorEntity);
                    fail.addAndGet(1);
                }else {
                    List<EmployeeExcelErrorEntity> list = employeeExcelErrorService.list(Wrappers.<EmployeeExcelErrorEntity>lambdaQuery()
                            .eq(EmployeeExcelErrorEntity::getCorpId,CorpContextHolder.getCorpId()));
                    list.forEach(l ->{
                        if (l.getName().equals(map.get("name"))&&l.getWxUserId().equals(map.get("userid"))){
                            employeeExcelErrorService.removeById(l.getId());
                        }
                    });
                    success.addAndGet(1);
                }
                i.getAndIncrement();
            });
            employeeExcelErrorService.saveBatch(errorEntities);
        } catch (NullPointerException e) {
            e.printStackTrace();
            return R.ok(e.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return R.ok("本次导入成功： "+success+"条，失败："+fail+"条");
    }

    @Override
    public String getUserIdById(Integer id) {
        WorkEmployeeEntity workEmployeeEntity = this.getById(id);
        String userId = workEmployeeEntity.getWxUserId();
        return userId;
    }

    @Override
    public String getNameById(Integer id) {
        WorkEmployeeEntity workEmployeeEntity = this.getById(id);
        String name = workEmployeeEntity.getName();
        return name;
    }


    /**
     * @description 获取用户通讯录详情
     * @author zhaojinjian
     * @createTime 2020/12/16 19:03
     */
    @Override
    public WorkEmployeeEntity getWorkEmployeeInfo(String userId) {
        //QueryWrapper<WorkEmployeeEntity> employeeWrapper = new QueryWrapper<>();
        //employeeWrapper.eq("wx_user_id", userId);
        //return this.baseMapper.selectOne(employeeWrapper);
        Integer corpId = CorpContextHolder.getCorpId();
        return this.getOne(Wrappers.<WorkEmployeeEntity>lambdaQuery().eq(WorkEmployeeEntity::getCorpId,corpId).eq(WorkEmployeeEntity::getWxUserId,userId));
    }

    /**
     * @description 根据子账户Id获取成员信息
     * @author zhaojinjian
     * @createTime 2020/12/23 18:34
     */
    @Override
    public List<WorkEmployeeEntity> getWorkEmployeeByLogUserId(Integer logUserId) {
        return this.list(Wrappers.<WorkEmployeeEntity>lambdaQuery()
                .eq(WorkEmployeeEntity::getLogUserId,logUserId)
                .eq(WorkEmployeeEntity::getStatus, 1));
    }

    @Override
    public List<WorkEmployeeEntity> getWorkEmployeeByUserId(String userId) {
        List<WorkEmployeeEntity> list = this.baseMapper.getWorkEmployeeByUserId(userId);
        return list;
    }

    /**
     * 根据员工id获取员工名称
     *
     * @param empIds
     * @return
     */
    @Override
    public String[] getEmployeeName(List<Integer> empIds) {
        QueryWrapper<WorkEmployeeEntity> employeeWrapper = new QueryWrapper<>();
        employeeWrapper.select("name");
        employeeWrapper.in("id", empIds);
//        employeeWrapper.isNull("deleted_at");
        return this.list(employeeWrapper).stream().map(WorkEmployeeEntity::getName).toArray(String[]::new);
    }

    /**
     * @description 获取企业下成员名称和id
     * @author zhaojinjian
     * @createTime 2021/1/7 12:51
     */
    @Override
    public Map<Integer, String> getCorpEmployeeName(Integer corpId, List<Integer> empIds) {
        CorpEntity corpEntity = corpService.getCorpInfoById(corpId);
        QueryWrapper<WorkEmployeeEntity> employeeWrapper = new QueryWrapper<>();
        employeeWrapper.select("name,id");
        employeeWrapper.eq("status",1);
        employeeWrapper.eq("corp_id", corpId);
        if (empIds != null && empIds.size() != 0) {
            employeeWrapper.in("id", empIds);
        }
        //employeeWrapper.isNull("deleted_at");
        List<WorkEmployeeEntity> list = this.baseMapper.selectList(employeeWrapper);
        Map<Integer, String> map = new HashMap<>();
        list.forEach(item -> {
            map.put(item.getId(), corpEntity.getCorpName() + "--" + item.getName());
        });
        return map;
    }

    @Override
    public Map<Integer, String> getEmployeeName(Integer corpId, List<Integer> empIds) {
        QueryWrapper<WorkEmployeeEntity> employeeWrapper = new QueryWrapper<>();
        employeeWrapper.select("name,id");
        employeeWrapper.eq("status",1);
        employeeWrapper.eq("corp_id", corpId);
        if (empIds != null && empIds.size() != 0) {
            employeeWrapper.in("id", empIds);
        }
        List<WorkEmployeeEntity> list = this.baseMapper.selectList(employeeWrapper);
        Map<Integer, String> map = new HashMap<>();
        list.forEach(item -> {
            map.put(item.getId(), item.getName());
        });
        return map;
    }

    /**
     * @description 获取企业下成员名称和id
     * @author zhaojinjian
     * @createTime 2021/1/7 12:51
     */
    @Override
    public JSONArray getCorpEmployeeName(Integer corpId, String searchKeyWords) {
        QueryWrapper<WorkEmployeeEntity> employeeWrapper = new QueryWrapper<>();
        employeeWrapper.select("name,id","wx_user_id");
        employeeWrapper.eq("corp_id", corpId);
        employeeWrapper.eq("status", 1);
        if (searchKeyWords != null && !searchKeyWords.isEmpty()) {
            employeeWrapper.like("name", searchKeyWords);
        }
//        employeeWrapper.isNull("deleted_at");
        List<WorkEmployeeEntity> list = this.list(employeeWrapper);
        JSONArray resultArray = new JSONArray();
        list.forEach(item -> {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("employeeId", item.getId());
            jsonObject.put("name", item.getName());
            jsonObject.put("wxUserId",item.getWxUserId());
            resultArray.add(jsonObject);
        });
        return resultArray;
    }

    /**
     * @description 根据企业id获取所有成员的微信UserId
     * @author zhaojinjian
     * @createTime 2020/12/18 14:21
     */
    @Override
    public Map<String, Integer> getCorpByUserId(Integer corpId) {
        QueryWrapper<WorkEmployeeEntity> employeeWrapper = new QueryWrapper<>();
        employeeWrapper.select("wx_user_id,id");
        employeeWrapper.eq("corp_id", corpId);
//        employeeWrapper.isNull("deleted_at");

        List<WorkEmployeeEntity> employeeList = this.list(employeeWrapper);
        if (employeeList != null && employeeList.size() > 0) {
            return employeeList.stream().collect(Collectors.toMap(WorkEmployeeEntity::getWxUserId, WorkEmployeeEntity::getId));
        }
        return null;
    }

    /**
     * @param userId,corpId
     * @description: 查询当前用户归属的公司
     * @return:
     * @author: Huayu
     * @time: 2020/12/1 11:15
     */
    @Override
    public List<WorkEmployeeEntity> getWorkEmployeeByLogUserId(String userId, String corpId) {
        QueryWrapper<WorkEmployeeEntity> QueryWrapper = new QueryWrapper<>();
        QueryWrapper.setEntity(new WorkEmployeeEntity());
        QueryWrapper.eq("log_user_id", userId);
        QueryWrapper.eq("corp_id", corpId);
        QueryWrapper.eq("status", 1);
        List<WorkEmployeeEntity> corpList = this.baseMapper.selectList(QueryWrapper);
        return corpList;
    }

    /**
     * @description: 查询登录用户通讯录信息
     * @return:
     * @author: Huayu
     * @time: 2020/12/1 14:26
     */
    @Override
    public List<WorkEmployeeEntity> getWorkEmployeeByCorpIdLogUserId(String corpId, String userId) {
        QueryWrapper<WorkEmployeeEntity> QueryWrapper = new QueryWrapper<>();
        QueryWrapper.select("id","corp_id","log_user_id");
        QueryWrapper.eq("corp_id", corpId);
        QueryWrapper.eq("log_user_id", userId);
        return this.baseMapper.selectList(QueryWrapper);
    }

    /**
     * @description: 查询员工
     * @return:
     * @author: Huayu
     * @time: 2020/12/10 18:39
     */
    @Override
    public List<WorkEmployeeEntity> getWorkEmployeesById(String ownerIdArr) {
        QueryWrapper<WorkEmployeeEntity> QueryWrapper = new QueryWrapper<WorkEmployeeEntity>();
        QueryWrapper.select("id,corp_id as corpId,name");
        QueryWrapper.in("id", ownerIdArr.split(","));
        return this.baseMapper.selectList(QueryWrapper);
    }

    /**
     * @description:企业通讯录成员模糊匹配
     * @author: Huayu
     * @time: 2020/12/16 11:22
     */
    @Override
    public List<WorkEmployeeEntity> getWorkEmployeesByCorpIdName(Integer corpId, String name, String clStr) {
        QueryWrapper<WorkEmployeeEntity> workEmployeeEntityQueryWrapper = new QueryWrapper();
        workEmployeeEntityQueryWrapper.select(clStr);
        workEmployeeEntityQueryWrapper.eq("corp_id", corpId);
        workEmployeeEntityQueryWrapper.like("name", name);
        return this.baseMapper.selectList(workEmployeeEntityQueryWrapper);
    }

    @Override
    public List<WorkEmployeeEntity> getWorkEmployeesByCorpId(Integer corpId, String clStr) {
        QueryWrapper<WorkEmployeeEntity> workEmployeeEntityQueryWrapper = new QueryWrapper();
        workEmployeeEntityQueryWrapper.select(clStr);
        workEmployeeEntityQueryWrapper.eq("corp_id", corpId);
        return this.baseMapper.selectList(workEmployeeEntityQueryWrapper);
    }

    @Override
    public List<WorkEmployeeEntity> getWorkEmployeesByMobile(String phone, String clStr) {
        QueryWrapper<WorkEmployeeEntity> workEmployeeEntityQueryWrapper = new QueryWrapper();
        workEmployeeEntityQueryWrapper.select(clStr);
        workEmployeeEntityQueryWrapper.eq("mobile",phone);
        return this.baseMapper.selectList(workEmployeeEntityQueryWrapper);
    }

    @Override
    public List<WorkEmployeeEntity> getWorkEmployeeList(String page, String perPage, String clStr, String empIdArr) {
        QueryWrapper<WorkEmployeeEntity> workEmployeeEntityQueryWrapper = new QueryWrapper();
        workEmployeeEntityQueryWrapper.select(clStr);
        if(empIdArr != null && !empIdArr.equals("")){
            String[] empIdStr = empIdArr.split(",");
            List<String> list = new ArrayList();
            for (String str:
                    empIdStr) {
                list.add(str);
            }
            workEmployeeEntityQueryWrapper.in("id",list);
        }
        IPage<WorkEmployeeEntity> pageModel = new Page<WorkEmployeeEntity>();
        pageModel.setCurrent(Long.parseLong(page));
        pageModel.setSize(Long.parseLong(perPage));
        return this.baseMapper.selectPage(pageModel,workEmployeeEntityQueryWrapper).getRecords();
    }

    @Override
    public Page getWorkEmployeeList(Page page, String clStr, String empIdArr, String employeeId, String employeeName) {
        QueryWrapper<WorkEmployeeEntity> workEmployeeEntityQueryWrapper = new QueryWrapper();
        workEmployeeEntityQueryWrapper.select(clStr);
        if(empIdArr != null && !empIdArr.equals("")){
            String[] empIdStr = empIdArr.split(",");
            List<String> list = new ArrayList();
            for (String str : empIdStr) {
                list.add(str);
            }
            workEmployeeEntityQueryWrapper.in("id",list);
        }
        if (employeeId != null && !"".equals(employeeId))
            workEmployeeEntityQueryWrapper.like("id", employeeId);
        if (employeeName != null && !"".equals(employeeName))
            workEmployeeEntityQueryWrapper.like("name", employeeName);
        return (Page) this.baseMapper.selectPage(page, workEmployeeEntityQueryWrapper);
    }

    @Override
    public List<WorkEmployeeEntity> getWorkEmployeesByCorpIdsWxUserId(Integer corpId, List<String> froms,List<String> tolists, String s) {
        QueryWrapper<WorkEmployeeEntity> workEmployeeEntityQueryWrapper = new QueryWrapper();
        workEmployeeEntityQueryWrapper.select(s);
        List<String> list = new LinkedList<>();
        list.addAll(froms);
        list.addAll(tolists);
        List<String> collect = list.stream().distinct().collect(Collectors.toList());
        workEmployeeEntityQueryWrapper.in("wx_user_id",collect);
        workEmployeeEntityQueryWrapper.eq("corp_id",corpId);
        return this.baseMapper.selectList(workEmployeeEntityQueryWrapper);
    }

    /**
     * 根据员工 id 列表获取员工微信 id
     *
     * @param empIdList
     */
    @Override
    public List<String> getWxEmpIdListByEmpIdList(List<Integer> empIdList) {
        if (Objects.isNull(empIdList) || empIdList.isEmpty()) {
            return Collections.emptyList();
        }
        return listByIds(empIdList).stream().map(WorkEmployeeEntity::getWxUserId).collect(Collectors.toList());
    }
    /**
     * 获取当前后管登陆者的部门权限
     */
    @Override
    public List<Integer> getAuthorityDept() {
        Integer logId = SecurityUtils.getUser().getId();
        Integer corpId = CorpContextHolder.getCorpId();
        Integer employeeId = this.getObj(Wrappers.<WorkEmployeeEntity>lambdaQuery().select(WorkEmployeeEntity::getId)
                .eq(WorkEmployeeEntity::getLogUserId, logId)
                .eq(WorkEmployeeEntity::getCorpId, corpId), o -> Integer.parseInt(o.toString()));
        List<Object> deptIds = workEmployeeDepartmentService.listObjs(Wrappers.<WorkEmployeeDepartmentEntity>lambdaQuery()
                .select(WorkEmployeeDepartmentEntity::getDepartmentId)
                .eq(WorkEmployeeDepartmentEntity::getEmployeeId, employeeId));
        ArrayList<Integer> finalDeptIds = new ArrayList<>();
        deptIds.forEach(f -> {
            List<Integer> allChilds = deptService.getAllChilds(Integer.parseInt(f.toString()));
            finalDeptIds.addAll(finalDeptIds);
        });
        return finalDeptIds.stream().distinct().collect(Collectors.toList());


    }

    @Override
    public R<WxEmpVo> getEmp(String mobile) {
        Integer corpId = getCorpId(false);

        List<WorkEmployeeEntity> emps = this.getWorkEmployeesByMobile(mobile,"*");
        if(emps.isEmpty()) {
            return R.failed(new WxEmpVo());
        }
        /*String respJson = WxApiUtils.getUser(emps.get(0).getWxUserId(), corpId);
        if (respJson == null) {
            return R.failed(new WxEmpVo());
        }
        cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(respJson);
        WxEmpVo vo = new WxEmpVo();
        BeanUtil.copyProperties(jsonObject, vo, new String[]{"department"});
        vo.setDepartment(JSONUtil.toJsonStr(jsonObject.getJSONArray("department")));*/

        WorkEmployeeEntity entity = emps.get(0);
        WxEmpVo vo = new WxEmpVo();
        vo.setGender(String.valueOf(entity.getGender()));
        vo.setUserid(entity.getMobile());
        vo.setMain_department(entity.getWxMainDepartmentId());
        vo.setMobile(entity.getMobile());
        vo.setName(entity.getName());
        List<Integer> depts = new ArrayList<>();
        depts.add(entity.getWxMainDepartmentId());
        vo.setDepartment(JSONUtil.toJsonStr(depts));

        return R.ok(vo);
    }

    @Override
    @Transactional
    public R<Boolean> addEmployee(WxEmpDto dto) {
        Integer corpId = getCorpId(true);

        Map<String,Object> entity = new HashMap<>();
        BeanUtil.copyProperties(dto, entity);
        List<Integer> departmentIds = new ArrayList<>();
        departmentIds.add(dto.getMain_department());
        entity.put("department",departmentIds);

        //企业微信端成员验证与创建
        String respJson = WxApiUtils.createUser(entity, corpId);
        cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(respJson);
        if (0 == jsonObject.getInt("errcode")) {
            log.debug("企业微信端成员创建成功");
        }
        else if (60102 == jsonObject.getInt("errcode") || 60104 == jsonObject.getInt("errcode")) {
            log.debug("企业微信端成员已经存在");
        }
        else {
            return R.failed(Boolean.FALSE);
        }

        //本地成员验证与创建
        int count = this.count(Wrappers.<WorkEmployeeEntity>lambdaQuery()
                .eq(WorkEmployeeEntity::getWxUserId, dto.getUserid())
                .eq(WorkEmployeeEntity::getCorpId, corpId));
        if(count > 0) {
            log.debug("本地成员已经存在");
        }
        else{
            //查询部门主键id
            WorkDeptEntity dept = deptService.getOne(Wrappers.<WorkDeptEntity>lambdaQuery()
                    .eq(WorkDeptEntity::getWxDepartmentId,dto.getMain_department())
                    .eq(WorkDeptEntity::getCorpId, corpId));

            //成员创建
            WorkEmployeeEntity we = new WorkEmployeeEntity();
            we.setCorpId(corpId);
            we.setWxUserId(dto.getUserid());
            we.setName(dto.getName());
            we.setMainDepartmentId(dept.getId());
            we.setWxMainDepartmentId(dto.getMain_department());
            we.setMobile(dto.getMobile());
            we.setGender(Integer.valueOf(dto.getGender()));
            this.save(we);
            //关联部门
            WorkEmployeeDepartmentEntity wed = new WorkEmployeeDepartmentEntity();
            wed.setEmployeeId(we.getId());
            wed.setDepartmentId(dept.getId());
            workEmployeeDepartmentService.save(wed);
            log.debug("本地成员创建成功");
        }

        return R.ok(Boolean.TRUE);
    }

    @Override
    public R<Boolean> updateEmployee(WxEmpDto dto) {
        Integer corpId = getCorpId(true);

        //企业微信端更新
        Map<String,Object> user = new HashMap<>();
        user.put("userid",dto.getUserid());
        user.put("gender",dto.getGender());
        user.put("name",dto.getName());
        String respJson = WxApiUtils.updateUser(user, corpId);
        if(respJson == null) {
            return R.failed(Boolean.FALSE);
        }
        log.debug("更新企业微信端成员成功");

        //本地更新
        WorkEmployeeEntity entity = new WorkEmployeeEntity();
        entity.setName(dto.getName());
        entity.setGender(Integer.valueOf(dto.getGender()));
        UpdateWrapper<WorkEmployeeEntity> uw = new UpdateWrapper<>();
        entity.update(Wrappers.<WorkEmployeeEntity>lambdaQuery()
                .eq(WorkEmployeeEntity::getWxUserId,dto.getUserid())
                .eq(WorkEmployeeEntity::getCorpId, corpId));
        log.debug("本地更新成功");

        return R.ok(Boolean.TRUE);
    }

    @Override
    public R<Boolean> deleteEmployee(String wxUserId) {
        Integer corpId = getCorpId(true);

        //企业微信端删除
        String respJson = WxApiUtils.deleteUser(wxUserId, corpId);
        cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(respJson);
        int errcode = jsonObject.getInt("errcode");
        if(errcode != 0 && errcode != 60111) {
            return R.failed(Boolean.FALSE);
        }
        log.debug("删除企业微信端成员成功");

        //本地删除
        WorkEmployeeEntity we = this.getOne(Wrappers.<WorkEmployeeEntity>lambdaQuery()
                .eq(WorkEmployeeEntity::getWxUserId,wxUserId)
                .eq(WorkEmployeeEntity::getCorpId, corpId));
        if(we == null) {
            return R.ok(Boolean.TRUE);
        }
        //1.删除成员与部门关联
        workEmployeeDepartmentService.remove(Wrappers.<WorkEmployeeDepartmentEntity>lambdaQuery()
                .eq(WorkEmployeeDepartmentEntity::getEmployeeId,we.getId()));
        //2.删除成员
        this.removeById(we.getId());

        log.debug("本地删除成功");

        return R.ok(Boolean.TRUE);
    }

    /**
     * 同步系统部门和用户
     * @param corpId
     */
    @Override
    public void synSysUserAndDept(int corpId) {
        syncSysDept(corpId);
        syncSysUser(corpId,null, CommonConstants.STATUS_NORMAL);
    }

    /**
     * 同步企业微信部门到系统部门
     * @param corpId
     */
    private void syncSysDept(int corpId) {
        //查询最新部门列表
        List<WorkDeptEntity> wxDeptList = deptService.getWorkDepartmentsByCorpId(String.valueOf(corpId));
        Map<Integer,WorkDeptEntity> wxDeptMap = new HashMap<>();
        for (WorkDeptEntity workDeptEntity : wxDeptList) {
            wxDeptMap.put(workDeptEntity.getWxDepartmentId(),workDeptEntity);
        }
        //查询系统当前部门列表
        R<List<SysWxDeptRelation>> result = remoteSyncSysService.getSysWxRelations(SecurityConstants.FROM_IN);
        if(result == null) {
            return;
        }
        List<SysWxDeptRelation> relationList = result.getData();
        if(relationList == null) {
            return;
        }
        Map<Integer,SysWxDeptRelation> sysWxRelationMap = new HashMap<>();
        for (SysWxDeptRelation relation : relationList) {
            sysWxRelationMap.put(relation.getWxDeptId(),relation);
        }

        //新增集合
        Map<Integer,WorkDeptEntity> insertMap = new HashMap<>();
        //更新集合
        Map<Integer,SyncSysDept> updateMap = new HashMap<>();
        //删除集合
        Map<Integer,SysWxDeptRelation> deleteMap = new HashMap<>();

        //过滤新增
        for (SysWxDeptRelation relation : relationList) {
            WorkDeptEntity workDeptEntity = wxDeptMap.remove(relation.getWxDeptId());
            if(workDeptEntity != null) {
                //过滤更新
                SyncSysDept syncSysDept = new SyncSysDept();
                syncSysDept.setOpt(1);
                syncSysDept.setDeptName(workDeptEntity.getName());
                syncSysDept.setWxDeptId(workDeptEntity.getWxDepartmentId());
                syncSysDept.setWxParentDeptId(workDeptEntity.getWxParentid());
                syncSysDept.setSysDeptId(sysWxRelationMap.get(workDeptEntity.getWxDepartmentId()).getSysDeptId());
                syncSysDept.setOrder(workDeptEntity.getOrder());
                updateMap.put(syncSysDept.getWxDeptId(),syncSysDept);
            }
        }
        insertMap = wxDeptMap;

        //过滤删除
        for (WorkDeptEntity workDeptEntity : wxDeptList) {
            SysWxDeptRelation relation = sysWxRelationMap.remove(workDeptEntity.getWxDepartmentId());
            if(relation != null) {
                //过滤更新
                SyncSysDept syncSysDept = new SyncSysDept();
                syncSysDept.setOpt(1);
                syncSysDept.setDeptName(workDeptEntity.getName());
                syncSysDept.setWxDeptId(workDeptEntity.getWxDepartmentId());
                syncSysDept.setWxParentDeptId(workDeptEntity.getWxParentid());
                syncSysDept.setSysDeptId(relation.getSysDeptId());
                syncSysDept.setOrder(workDeptEntity.getOrder());
                updateMap.put(syncSysDept.getWxDeptId(),syncSysDept);
            }
        }
        deleteMap = sysWxRelationMap;

        List<SyncSysDept> trees = new ArrayList<>();
        //构建部门树
        buildTree(wxDeptList, 0, trees, insertMap, updateMap, deleteMap);

        //创建同步时通过wxParentId查询父部门的map
        Map<Integer,SyncSysDept> syncSysDeptMap = new HashMap<>();
        for (SyncSysDept node : trees) {
            syncSysDeptMap.put(node.getWxDeptId(),node);
        }
        //过滤完整树
        for (int len = trees.size()-1,i=len; i>-1; i--) {
            SyncSysDept node = trees.get(i);
            if(node.getWxParentDeptId() != 0) {
                trees.remove(i);
            }
        }
        //将删除节点添加到集合最后
        deleteMap.values().forEach(relation -> {
            SyncSysDept syncSysDept = new SyncSysDept();
            syncSysDept.setOpt(2);
            syncSysDept.setWxDeptId(relation.getWxDeptId());
            syncSysDept.setSysDeptId(relation.getSysDeptId());
            trees.add(syncSysDept);
        });

        //远程调用系统部门接口同步数据
        String jsonTrees = JSONUtil.toJsonStr(trees);
        String jsonSysnSysDeptMap = JSONUtil.toJsonStr(syncSysDeptMap);
        Map<String,String> param = new HashMap<>();
        param.put("trees",jsonTrees);
        param.put("syncDeptMap",jsonSysnSysDeptMap);
        remoteSyncSysService.onSyncWxDept(param, SecurityConstants.FROM_IN);
    }

    /**
     * 同步企业微信成员到系统用户
     * @param corpId
     */
    @Override
    public void syncSysUser(int corpId, String wxUserId, String delFlag) {
        //查询全部成员
        List<WorkEmployeeEntity> empList = this.list(Wrappers.<WorkEmployeeEntity>lambdaQuery()
                .eq(StrUtil.isNotEmpty(wxUserId),WorkEmployeeEntity::getWxUserId, wxUserId)
                .orderByAsc(WorkEmployeeEntity::getWxMainDepartmentId));
        if (empList.isEmpty()) {
            return;
        }

        //查询系统当前部门列表
        R<List<SysWxDeptRelation>> result = remoteSyncSysService.getSysWxRelations(SecurityConstants.FROM_IN);
        Map<Integer,Integer> relationMap = new HashMap<>();
        if(result != null && result.getData() != null) {
            List<SysWxDeptRelation> relationList = result.getData();
            relationList.stream().forEach(relation -> {
                relationMap.put(relation.getWxDeptId(),relation.getSysDeptId());
            });
        }else {
            return;
        }

        //设置成员
        List<SysUser> userList = new ArrayList<>();
        empList.stream().forEach(emp -> {
            Integer wxDeptId = emp.getWxMainDepartmentId();
            if (relationMap.get(wxDeptId) == null || StrUtil.isEmpty(emp.getMobile())) {
                return;
            }
            SysUser user = new SysUser();
            if (CommonConstants.STATUS_DEL.equals(delFlag)) {
                user.setUsername(emp.getMobile());
                user.setName(emp.getName());
                user.setDelFlag(delFlag);
            }else {
                user.setUsername(emp.getMobile());
                user.setName(emp.getName());
                user.setPhone(emp.getMobile());
                user.setDeptId(relationMap.get(wxDeptId));
                user.setAvatar(emp.getAvatar());
                user.setLockFlag("0");
                user.setDelFlag(CommonConstants.STATUS_NORMAL);
            }
            userList.add(user);
        });
        if (userList.isEmpty()) {
            return;
        }

        //远程同步服务调用
        Map<String,String> userMap = new HashMap<>(1);
        userMap.put("users",JSONUtil.toJsonStr(userList));
        remoteSyncSysService.onSyncWxEmp(userMap,SecurityConstants.FROM_IN);
    }

    /**
     * 通过SyncSysDept创建树形节点
     *
     * @param wxDepts
     * @param root
     * @return
     */
    private List<SyncSysDept> buildTree(List<WorkDeptEntity> wxDepts,
                                       int root,
                                       List<SyncSysDept> trees,
                                       Map<Integer,WorkDeptEntity> insertMap,
                                       Map<Integer,SyncSysDept> updateMap,
                                       Map<Integer,SysWxDeptRelation> deleteMap) {

        if(trees == null) {
            trees = new ArrayList<>();
        }

        SyncSysDept node;
        for (WorkDeptEntity wxDept : wxDepts) {
            node = new SyncSysDept();
            node.setWxDeptId(wxDept.getWxDepartmentId());
            node.setWxParentDeptId(wxDept.getWxParentid());
            node.setDeptName(wxDept.getName());

            if(insertMap.get(wxDept.getWxDepartmentId()) != null) {
                node.setOpt(0);
                node.setOrder(wxDept.getOrder());
            }
            else if(updateMap.get(wxDept.getWxDepartmentId()) != null) {
                SyncSysDept syncSysDept = updateMap.get(wxDept.getWxDepartmentId());
                node.setOpt(1);
                node.setSysDeptId(syncSysDept.getSysDeptId());
            }

            trees.add(node);
        }
        return build(trees, root);
    }

    /**
     * 两层循环实现建树
     *
     * @param treeNodes 传入的树节点列表
     * @return
     */
    private List<SyncSysDept> build(List<SyncSysDept> treeNodes,Object root) {

        List<SyncSysDept> trees = new ArrayList<>();

        for (SyncSysDept treeNode : treeNodes) {

            if (root.equals(treeNode.getWxParentDeptId())) {
                treeNode.setSysParentDeptId(0);
                trees.add(treeNode);
            }

            for (SyncSysDept it : treeNodes) {
                if (it.getWxParentDeptId() == treeNode.getWxDeptId()) {
                    if (treeNode.getChildren() == null) {
                        treeNode.setChildren(new ArrayList<>());
                    }
                    //添加子节点
                    treeNode.add(it);
                }
            }
        }

        return trees;
    }

    /**
     * 获取企业
     * @return
     */
    private Integer getCorpId(boolean isEx) {
        List<CorpEntity> list = corpService.list();
        if (list.isEmpty()) {
            if (isEx) {
                throw new CheckedException("企业不存在");
            }
            return null;
        }
        return list.get(0).getCorpId();
    }



    public Integer getEmpIdByWxUserId(String wxUserId) {
        WorkEmployeeEntity entity = this.getOne(
                Wrappers.<WorkEmployeeEntity>lambdaQuery()
                        .eq(WorkEmployeeEntity::getWxUserId, wxUserId)
                        .eq(WorkEmployeeEntity::getDelFlag, 0), false
        );
        if (entity != null) {
            return entity.getId();
        }
        return null;
    }

}
